package com.lj.back.manage.scaffold.common.util;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.google.gson.*;
import com.lj.back.manage.scaffold.common.constant.Constant;
import com.lj.back.manage.scaffold.common.enums.ResponseEnum;
import com.lj.back.manage.scaffold.common.exception.MyException;
import com.lj.back.manage.scaffold.common.response.R;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.util.CastUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 公共工具类
 * @author lvlaotou
 * @version 1.0.0
 */
public class CommonUtil {

    private CommonUtil(){}

    /**
     * 获取去掉-的uuid
     * @return 去掉-的uuid
     */
    public static String getUUID(){
        return UUID.randomUUID().toString().replace("-","");
    }

    /**
     * 对用户输入内容进行过滤
     * @param input 输入内容
     * @return 过滤后的内容
     */
    public static String inputFilter(String input){
        if(StringUtils.isBlank(input)){
            return null;
        }
        input = StringEscapeUtils.escapeHtml4(input);
        return input;
    }

    /**
     * 序列化对象
     */
    public static final Gson GSON = new GsonBuilder()
            .setDateFormat(Constant.DATE_TIME_FORMAT)
            .registerTypeAdapter(LocalDateTime.class, (JsonSerializer<LocalDateTime>) (localDateTime, type, jsonSerializationContext) -> new JsonPrimitive(localDateTime.format(DateTimeFormatter.ofPattern(Constant.DATE_TIME_FORMAT))))
            .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDateTime>) (jsonElement, type, jsonDeserializationContext) -> {
                String datetime = jsonElement.getAsJsonPrimitive().getAsString();
                return LocalDateTime.parse(datetime, DateTimeFormatter.ofPattern(Constant.DATE_TIME_FORMAT));
            })
            .registerTypeAdapter(LocalDate.class, (JsonSerializer<LocalDate>) (localDate, type, jsonSerializationContext) -> new JsonPrimitive(localDate.format(DateTimeFormatter.ofPattern(Constant.DATE_FORMAT))))
            .registerTypeAdapter(LocalDateTime.class, (JsonDeserializer<LocalDate>) (jsonElement, type, jsonDeserializationContext) -> {
                String datetime = jsonElement.getAsJsonPrimitive().getAsString();
                return LocalDate.parse(datetime, DateTimeFormatter.ofPattern(Constant.DATE_FORMAT));
            })
            .create();

    /**
     * 格式化json  去掉包裹k  v 的"
     * @param json 需要格式化的json
     * @return 格式化后的json
     */
    public static String jsonFormat(final String json){
        Assert.assertNotNull(json,"需要被格式化的json不能为空");
        HashMap<String, String> format = Maps.newHashMapWithExpectedSize(4);
        format.put("{\"","{");
        format.put("\"}","}");
        format.put("\"]","]");
        format.put("[\"","[");
        format.put(",\"",",");
        format.put(":\"",":");
        format.put("\":",":");
        format.put("\",",",");
        String jsonFormat = json;
        Set<Map.Entry<String, String>> entries = format.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            if (jsonFormat.contains(entry.getKey())){
                jsonFormat = jsonFormat.replace(entry.getKey(),entry.getValue());
            }
        }
        return jsonFormat;
    }

    /**
     * mybatis plus 分页对象类型转换
     * @param source 源对象
     * @param target 目标对象
     * @param <T> 分页对象枚举对象
     * @param <S> 目标对象
     * @return 新的分页对象
     */
    public static  <T,S> IPage<T> pageBeanConvert(IPage<S> source, Class<T> target){
        List<T> collect = source.getRecords().stream()
                .map(s -> BeanUtil.copyProperties(s, target))
                .collect(Collectors.toList());
        IPage<T> targetPage = new Page<>();
        BeanUtil.copyProperties(source,targetPage);
        targetPage.setRecords(collect);
        return targetPage;
    }

    /**
     * 根据异常类型获取返回对象
     * @param e 异常信息
     * @return R
     */
    public static R<Object> getExceptionResult(Exception e){
        if (e instanceof MyException ){
            return R.build(ResponseEnum.ERROR).message(e.getMessage()).code(((MyException)e).getCode());
        }
        if (e instanceof MethodArgumentNotValidException || e instanceof BindException){
            BindingResult bindingResult = null;
            if (e instanceof MethodArgumentNotValidException){
                MethodArgumentNotValidException cast = CastUtils.cast(e);
                bindingResult = cast.getBindingResult();
            }
            if (e instanceof BindException){
                BindException cast = CastUtils.cast(e);
                bindingResult = cast.getBindingResult();
            }
            Assert.assertNotNull(bindingResult, "异常类型错误");
            String message = "参数错误:";
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null){
                message += fieldError.getDefaultMessage();
            }
            return R.build(ResponseEnum.PARAM_ERROR).message(message);
        }
        return R.build(getResponseEnumByException(e));
    }

    /**
     * 通过异常获取返回枚举对象
     * @param e 异常
     * @return ResponseEnum
     */
    public static ResponseEnum getResponseEnumByException(Exception e){
        if (e instanceof MyException ){
            return ResponseEnum.ERROR;
        }
        if (e instanceof MethodArgumentNotValidException || e instanceof BindException){
            return ResponseEnum.PARAM_ERROR;
        }
        if (e instanceof AuthorizationException){
            return ResponseEnum.AUTHORIZATION_INSUFFICIENT_ERROR;
        }
        if (e instanceof NoHandlerFoundException){
            return ResponseEnum.PATH_NOT_FOUND;
        }
        if (e instanceof DuplicateKeyException){
            return ResponseEnum.DATABASE_EXIST_ERROR;
        }
        return ResponseEnum.ERROR;
    }
}
